/*
 * Tree.java
 *
 * Created on July 4, 2006, 12:59 PM
 *
 */

package galronnlp.util;

import java.util.LinkedList;

/**
 *
 * @author Daniel A. Galron
 */
public abstract class Tree {
    public static final int LEXICAL = 0;
    public static final int UNARY   = 1;
    public static final int BINARY  = 2;
    public static final int NARY    = 3;
    
    protected Symbol category;
    protected double probability;
    protected int type;
    
    protected LinkedList children = new LinkedList();
    protected Tree parent = null;
    
    /** An object for generating String representations of this Tree.
     *  By default, it's a PennTreebank-style TreeStringGenerator that displays
     *  the inside probabilities of Trees.
     */
    protected TreeStringGenerator stringGen = new PennTreebankStringTreeGenerator(false);
    
    public void setParent(Tree p) {
        this.parent = p;
    }
    
    public Tree parent() {
        return parent;
    }
    
    /**
     * Added by D.N. Mehay: 12 Dec 2006.
     * @param cat A new <code>Symbol<code> replacing the old
     * category.
     * @return <code>null<code>.
     */
    public void setCat(Symbol cat) {
        this.category = cat;
    }
    
    public Symbol cat() {
        return category;
    }
    
    /* Added by D.N. Mehay: 12 Sep 2006. Checks to see
     * whether this is the root of the Tree.
     */
    public boolean isRoot() {
        return parent == null;
    }
    
    /* Added by D.N. Mehay: 12 Sep 2006 (needed for refactoring
     * the generation of String versions of Tree's into a
     * set of classes that are composed with Tree's).
     */
    public LinkedList getChildren() {
        return children;
    }
    
    /* Added by D.N. Mehay: 04 Jan 2007 (needed to be able to quickly
     * replace the list of children when performing a selective left-corner
     * transform).
     */
    public void setChildren(LinkedList newChildren) {
        this.children = newChildren;
    }
    
    public double prob() {
        return probability;
    }
    
    public int type() {
        return type;
    }
    
    public String toString() {
        // Generate a multiline (indented) version of this Tree with outermost
        // indentation level 0.
        return this.stringGen.generateMultilineString(this,0);
    }
    
    /** 
     * toString with the choice as to whether it will appear on multiple lines .
     * (D.N.M.).
     */
    public String toString(boolean indented) {
        if(indented) {
            return this.toString();
        } else {
            return this.stringGen.generateSingleLineString(this);
        }
    }
    
    public abstract LinkedList<Symbol> RHS();
    //public abstract void addToGrammar(Grammar g);
    
    public Symbol getLabel(int parentIndex, int siblingIndex) {
        Tree level = this;
        for(int i = 0; i < parentIndex; i++) {
            level = level.parent();
            if(level == null) {
                return null;
            }
        }
        Tree tParentLevel = level.parent();
        if(tParentLevel == null && siblingIndex != 0)
            return null;
        else if(tParentLevel == null && siblingIndex == 0)
            return level.cat();
        int thisIndex = tParentLevel.children.indexOf(level);
        int targetIndex = thisIndex - siblingIndex;
        if(targetIndex < 0)
            return null;
        return ((Tree)tParentLevel.children.get(targetIndex)).cat();
    }
}
